from flask import Blueprint
from extensions.init_csrf import csrf

index_bp = Blueprint('index', __name__, url_prefix='/')  # 蓝图名称 所在模块文件名称 指定url前缀


@index_bp.route('/')
def index():
    """首页"""

    res = '首页'

    return res


@csrf.exempt
@index_bp.route('/format_doc', methods=['GET', 'POST'])
def handle_process_document():
    """处理 web上传的文件"""
    from os import path, listdir
    from core.sysuser import split_path, reset_dir
    from flask import request, jsonify
    from extensions import log_gen

    dir_p = path.split(path.realpath(__file__))[0]  # 当前文件的文件夹路径
    report_p = split_path(dir_p, 'process_documents/report')  # 缓存reports
    project_p = split_path(dir_p, 'process_documents/project')  # 缓存process

    # GET/POST
    if request.method == 'GET':
        global base_data  # 申明引用外部的全局变量
        global struct_data

        for file in listdir(report_p):
            doc_path = split_path(report_p, file)  # 文件路径
            return handle_report(doc_path, report_p)  # 返回处理结果
        return jsonify({'code': 202, 'msg': '报告不存在'})
    else:
        files = request.files.getlist('file_data')  # 返回文件数据对象的列表

        if 'file_data' in list(request.files):  # 判断上传是否成功
            if reset_dir([report_p, project_p]) == 0:  # 清空缓存 不存在则自动创建
                log_gen.lgr.error('[ request err ] 缓存数据清除错误')
                return jsonify({"code": 500, "msg": '缓存数据清除错误'})

            doc_path = split_path(report_p, files[0].filename)  # 文件路径
            # TODO 存在保存异常的可能
            files[0].save(doc_path)  # 保存文件

            base_data = None  # 清除全局的数据
            struct_data = None

            return handle_report(doc_path, report_p)  # 返回处理结果
        else:
            log_gen.lgr.error('[ request err ] 请求错误')
            return jsonify({"code": 400, "msg": '请求错误'})


base_data = None  # 使用全局变量减少恢复数据的速度
struct_data = None


def handle_report(path_d, path_r):
    """
    处理报告的封装函数
    :param path_d 报告文件的路径
    :param path_r 报告文件的目录路径
    """
    from core.worder import get_doc_info
    from core.sysuser import reset_dir
    from extensions import log_gen
    from flask import jsonify

    global base_data  # 申明引用外部的全局变量
    global struct_data

    if base_data is None and struct_data is None:
        base_data, struct_data = get_doc_info(path_d)  # 获取报告信息
        if base_data is None or struct_data is None:
            reset_dir(path_r)  # 清除缓存
            log_gen.lgr.error('[ request err ] 缓存数据清除错误')
            return jsonify({"code": 404, "msg": '文件名称或格式内容不正确'})
        log_gen.lgr.info('[ request info ] 请求成功')
        return jsonify({
            "code": 200,
            "msg": '请求成功',
            'base': base_data})  # 回传基本数据
    else:
        # TODO 存在数据格式被篡改的风险
        log_gen.lgr.info('[ request info ] 请求成功')
        return jsonify({
            "code": 206,
            "msg": '数据还原成功',
            'base': base_data})  # 回传基本数据


@csrf.exempt
@index_bp.route('/down_zip', methods=['POST'])
def handle_document_zip():
    """处理 web下载的压缩文件"""
    from zipfile import ZipFile, ZIP_DEFLATED
    from datetime import datetime
    from os import remove, path, listdir
    from flask import send_from_directory, request, jsonify
    from core.sysuser import split_path, reset_dir
    from core.worder import replace_doc_info,replace_doc_info_single
    from extensions import log_gen, log_err

    dir_p = path.split(path.realpath(__file__))[0]  # 当前文件的文件夹路径
    report_p = split_path(dir_p, 'process_documents/report')  # 缓存reports
    project_p = split_path(dir_p, 'process_documents/project')  # 缓存project
    template_p = split_path(dir_p, 'process_documents/template')  # 缓存template
    reset_dir([report_p, project_p], mode=0)  # 触发创建/不删除文件
    now_date = datetime.now().strftime('%Y%m%d%H%M%S')  # 获取当前时间
    zip_path = None  # 设置初始值

    global base_data  # 申明引用外部的全局变量
    global struct_data

    if base_data is None or struct_data is None:
        log_gen.lgr.error('[ logic err ] 替换文档的字典数据异常 请重新上传文件 生成数据')
        return jsonify({"code": 500, "msg": '替换文档的字典数据异常 请重新上传文件 生成数据'})

    if len(listdir(report_p)) == 0:
        log_gen.lgr.error('[ request err ] 请先上传测评报告')
        return jsonify({"code": 404, "msg": '请先上传测评报告'})

    data = {}  # 使用新的变量 避免全局变量不能复用
    for k, v in request.form.items():  # 数据
        if k == '$被测单位负责人姓名$':  # 用于处理特定关键字 处理空值
            if v == '':
                v = '/'
        elif k == '$被测单位负责人联系电话$':
            if v == '':
                v = '/'
        data[k] = v
    if isinstance(base_data, dict):
        for k, v in base_data.items():
            if not data.__contains__(k):  # 处理页面未渲染使用的数据
                data[k] = v
    if isinstance(struct_data, dict):
        for k, v in struct_data.items():
            if not data.__contains__(k):
                data[k] = v

    for report in listdir(report_p):
        if '测评报告' not in report:
            log_gen.lgr.error('[ request err ] 不存上传的测评报告')
            return jsonify({"code": 404, "msg": '不存上传的测评报告'})

        rep = replace_doc_info(data, split_path(report_p, report), template_p, project_p)
        # rep = replace_doc_info_single(data, split_path(report_p, report), template_p, project_p)
        if rep is None:
            log_gen.lgr.error('[ server err ] 归档文件生成失败')
            return jsonify({"code": 500, "msg": '归档文件生成失败'})

        file_name = report.strip('.docx')  # 报告名称
        zip_path = split_path(project_p, f'{file_name}_{now_date}.zip')  # 只赋值最新的zip

        with ZipFile(zip_path, 'w', compression=ZIP_DEFLATED) as zp:  # 设置zip对象
            for file_n in listdir(project_p):
                file_p = split_path(project_p, file_n)
                if file_n.split('.')[-1] == 'zip':
                    if zip_path != file_p:
                        remove(file_p)  # 删除旧的zip文件
                    continue
                try:
                    zp.write(file_p, file_n)  # 写入zip中
                except Exception as e:
                    log_err.set_log_message('ERROR')
                    return jsonify({"code": 500, "msg": '压缩文件路径获取错误'})

        break  # 只读取一次

    if zip_path is None:
        log_gen.lgr.error('[ request err ] 不存上传的测评报告')
        return jsonify({"code": 404, "msg": '不存上传的测评报告'})
    else:
        try:
            file_n = zip_path.split('\\')[-1].encode('utf-8').decode('utf-8')
            return send_from_directory(project_p, file_n, as_attachment=True)
        except Exception as e:
            log_err.set_log_message('ERROR')
            return jsonify({"code": 500, "msg": '响应数据处理错误导致未响应'})


def test_response_single_txt():
    """测试返回 txt文本"""
    from sys import path as os_path
    from flask import make_response, send_from_directory

    response = make_response(
        send_from_directory(
            os_path.join(os_path[0], 'data/process_documents/project'),
            'ttt.txt', as_attachment=True))
    response.headers['content-disposition'] = 'filename=ttt.txt'
    return response


def test_read_file_flow(path):
    """测试读取文件的流"""
    from flask import Response

    def send_file(file_p):
        with open(file_p, 'rb') as tf:
            while 1:
                data = tf.read(1 * 1024 * 1024)  # 每次读取1MB 限速读取
                if not data:
                    break
                yield data

    response = Response(send_file(path), content_type='application/octet-stream')
    response.headers["Content-disposition"] = 'attachment; filename=%s' % path.split('\\')[-1]  # 如果不加上这行代码，导致下图的问题
    return response


if __name__ == '__main__':
    pass
